package com.ilearn.iodata.iolingo.service.processor.core.query;

import com.ilearn.iodata.iolingo.service.GetCollectionService;
import com.ilearn.iodata.iolingo.service.processor.GenericODataBaseProcessor;
import com.ilearn.iodata.iolingo.service.processor.core.api.GenericODataPage;
import com.ilearn.iodata.iolingo.utils.OlingoUtil;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;

import java.util.Locale;

import static org.apache.olingo.server.api.uri.UriResourceKind.count;

/**
 * Created by lyndon on 2018/6/7.
 */
public class GenericJoinQuery extends GenericODataBaseProcessor {

    private String sql;

    private EdmEntitySet edmEntitySet;

    private UriInfo uriInfo;

    private String whereClause;

    private String selectClause;

    private String orderByClause;


    public GenericJoinQuery(OData odata, UriInfo uriInfo, EdmEntitySet edmEntitySet, GenericODataPage page) throws ODataApplicationException, SerializerException {

        this.edmEntitySet = edmEntitySet;
        this.uriInfo = uriInfo;

        try {
            whereClause = getFilter2WhereClause(uriInfo, edmEntitySet);
        } catch (ExpressionVisitException e) {
            throw new ODataApplicationException(e.getMessage(), 409, Locale.ENGLISH);
        } catch (ODataApplicationException e) {
            e.printStackTrace();
        }

        selectClause = OlingoUtil.getSelectClause(odata, uriInfo, edmEntitySet.getEntityType());

        orderByClause = getOrderByStr(uriInfo);

        if (page != null) {
            int top = page.getTop();

            int skip = page.getSkip();

            String skiptoken = page.getSkiptoken();
        }


        sql = prepareHQL(selectClause, whereClause, edmEntitySet, orderByClause);

        //System.out.println("SQL:" + sql);
    }


    public void fetchEntityCollection(GetCollectionService getCollectionService, EntityCollection entityCollection) {
        getCollection(getCollectionService, edmEntitySet, sql, entityCollection);
    }


    public EntityCount fetchEntityCount(GetCollectionService getCollectionService) {
        CountOption countOption = uriInfo.getCountOption();
        if (countOption != null) {
            Boolean hasCount = countOption.getValue();
            if (hasCount) {
                String countSQL = prepareCountHQL(selectClause, whereClause, edmEntitySet);

                EntityCount entityCount = new EntityCount();
                entityCount.setCount(getCollectionCount(getCollectionService, countSQL));
                entityCount.setCountOption(countOption);
                return entityCount;
            }
        }

        EdmEntitySet edmEntitySet = Util.determineTargetEntitySet(uriInfo.getUriResourceParts());
        final int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
        final UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
        UriResourceKind kind = lastPathSegment.getKind();
        if (kind.equals(count)){
            String countSQL = prepareCountHQL(selectClause, whereClause, edmEntitySet);

            EntityCount entityCount = new EntityCount();
            entityCount.setCount(getCollectionCount(getCollectionService, countSQL));
            entityCount.setCountOption(countOption);
            return entityCount;
        }

        return null;
    }

    public class EntityCount {
        private CountOption countOption;
        private Integer count;

        public CountOption getCountOption() {
            return countOption;
        }

        public void setCountOption(CountOption countOption) {
            this.countOption = countOption;
        }

        public Integer getCount() {
            return count;
        }

        public void setCount(Integer count) {
            this.count = count;
        }
    }


}
